import {
  AfterViewInit,
  ChangeDetectorRef,
  ComponentRef,
  Directive,
  ElementRef,
  inject,
  Injector,
  Input,
  NgZone,
  OnDestroy,
  StaticProvider,
  ViewContainerRef
} from '@angular/core';
import { MAT_SNACK_BAR_DATA, MatSnackBar, MatSnackBarConfig, MatSnackBarRef } from '@angular/material/snack-bar';
import { BreakpointObserver } from '@angular/cdk/layout';
import { Subscription } from 'rxjs';
import { ToastService } from '@core/services/toast.service';
import { HideToastConfig, ToastMessage, ToastPanelData } from '@shared/models/toast.models';
import { ToastComponent } from './toast.component';

/**
 * Toast 指令
 * 
 * * 使用方式：
 * ```html
 * <div cne-toast></div>
 * <div cne-toast toastTarget="sidebar"></div>
 * ```
 */
@Directive({
  selector: '[cne-toast]',
  standalone: true
})
export class ToastDirective implements AfterViewInit, OnDestroy {
  
  @Input() toastTarget = 'root'; // 目标容器标识，用于区分不同的 Toast 显示区域

  private readonly elementRef = inject(ElementRef); // 指令所在元素的引用
  private readonly viewContainerRef = inject(ViewContainerRef); // 视图容器引用，用于动态创建组件
  private readonly toastService = inject(ToastService); // Toast 服务，负责接收通知消息
  private readonly snackBar = inject(MatSnackBar); // Material SnackBar 服务，用于显示 Material 风格的 Toast
  private readonly ngZone = inject(NgZone); // Angular 区域服务，用于确保更新在正确区域执行
  private readonly breakpointObserver = inject(BreakpointObserver); // 响应式断点监听器，用于判断屏幕尺寸
  private readonly cd = inject(ChangeDetectorRef); // 变更检测器，用于手动触发变更检测

  private notificationSubscription?: Subscription; // 通知消息订阅
  private hideNotificationSubscription?: Subscription; // 隐藏通知订阅
  
  private snackBarRef?: MatSnackBarRef<unknown>; // SnackBar 引用（SnackBar 模式）
  private toastPanelRef?: ComponentRef<ToastComponent>; // 自定义面板引用（自定义面板模式）

  private currentMessage?: ToastMessage; // 当前显示的消息，用于去重判断

  private dismissTimeout?: ReturnType<typeof setTimeout>; // 自动关闭定时器

  ngAfterViewInit(): void {
    this.notificationSubscription = this.toastService.getNotification().subscribe(
      (notificationMessage: ToastMessage) => {
        if (this.shouldDisplayMessage(notificationMessage)) {
          this.currentMessage = notificationMessage; // 保存当前消息，用于去重判断
          
          // 判断是否为桌面端（宽度 >= 960px）
          const isGtSm = this.breakpointObserver.isMatched('(min-width: 960px)');
          
          // 显示策略选择：
          // - 桌面端 + 自定义容器（sidebar/dialog等）→ Toast Panel（自定义面板）
          // - 移动端 或 root 容器 → SnackBar（Material 组件）
          if (isGtSm && this.toastTarget !== 'root') {
            this.showToastPanel(notificationMessage);
          } else {
            this.showSnackBar(notificationMessage, isGtSm);
          }
        }
      }
    );

    this.hideNotificationSubscription = this.toastService.getHideNotification().subscribe(
      (hideNotification: HideToastConfig) => {
        if (hideNotification) {
          const target = hideNotification.target || 'root'; // 获取目标容器
          if (this.toastTarget === target) { // 只有目标容器匹配时才隐藏
            this.currentMessage = undefined;// 清除当前消息状态
            this.ngZone.run(() => { // 在 Angular 区域中执行关闭操作
              this.snackBarRef?.dismiss(); // 关闭 SnackBar 模式
              if (this.toastPanelRef) {  // 模拟点击关闭按钮，关闭自定义面板模式
                this.toastPanelRef.instance.actionButton._elementRef.nativeElement.click();
              }
            });
          }
        }
      }
    );
  }

  /** 显示自定义面板 - 适用于桌面端非 root 容器 */
  private showToastPanel(toastMessage: ToastMessage): void {
    this.ngZone.run(() => {
      if (this.snackBarRef) {  // 关闭可能存在的 SnackBar
        this.snackBarRef.dismiss();
      }
      
      if (this.toastPanelRef) {  // 清理之前的 Toast Panel 组件
        this.viewContainerRef.detach(0);
        this.toastPanelRef.destroy();
      }

      const panelClass = this.buildPanelClass(toastMessage); // 构建面板样式类数组（控制位置和样式）
      
      const data: ToastPanelData = {
        notification: toastMessage,
        panelClass,
        // 销毁回调：组件关闭时移除
        destroyToastComponent: () => {
          this.viewContainerRef.detach(0);
          this.toastPanelRef?.destroy(); // ?. 不确定是否为 null/undefined → 用 ?. 避免报错
        }
      };

      // 创建注入器，提供 MAT_SNACK_BAR_DATA
      // ToastComponent 需要注入这个数据，所以使用统一的令牌
      const providers: StaticProvider[] = [
        { provide: MAT_SNACK_BAR_DATA, useValue: data }
      ];
      // 使用 ViewContainerRef 的注入器作为父级，确保依赖注入正确
      const injector = Injector.create({ 
        parent: this.viewContainerRef.injector, 
        providers 
      });
      
      // 动态创建 Toast 组件到视图容器中
      this.toastPanelRef = this.viewContainerRef.createComponent(ToastComponent, { index: 0, injector });
      
      // 手动触发变更检测，确保组件正确渲染
      // 特别是当父组件使用 OnPush 或异步创建组件时
      this.cd.detectChanges();

      // 如果设置了自动关闭时间，启动定时器
      if (toastMessage.duration && toastMessage.duration > 0) {
        // 额外加 500ms 给动画时间
        this.setDismissTimeout(toastMessage.duration + 500);
      }
    });
  }

  /** 
   * 构建面板样式类数组 - 控制位置和样式 
   * 
   * @param toastMessage - Toast 消息配置
   * @returns CSS 类名数组，例如：['cne-toast-panel', 'toast-panel', 'left', 'top']
   */
  private buildPanelClass(toastMessage: ToastMessage): string[] {
    let panelClass = ['cne-toast-panel', 'toast-panel']; // 基础类名
    
    if (toastMessage.panelClass) {  // 添加自定义面板类
      if (typeof toastMessage.panelClass === 'string') {
        panelClass.push(toastMessage.panelClass);
      } else if (toastMessage.panelClass.length) {
        panelClass = panelClass.concat(toastMessage.panelClass);
      }
    }

    // 获取位置配置
    const horizontalPosition = toastMessage.horizontalPosition || 'left';
    const verticalPosition = toastMessage.verticalPosition || 'top';

    // 水平位置类名映射
    if (horizontalPosition === 'start' || horizontalPosition === 'left') {
      panelClass.push('left');
    } else if (horizontalPosition === 'end' || horizontalPosition === 'right') {
      panelClass.push('right');
    } else {
      panelClass.push('h-center'); // 水平居中
    }

    // 垂直位置类名映射
    if (verticalPosition === 'top') {
      panelClass.push('top');
    } else {
      panelClass.push('bottom');
    }

    return panelClass;
  }

  /** 显示 SnackBar - 适用于移动端或 root 容器 */
  private showSnackBar(toastMessage: ToastMessage, isGtSm: boolean): void {
    this.ngZone.run(() => {
      this.snackBarRef?.dismiss(); // 关闭可能存在的 SnackBar

      // 准备传递给 SnackBar 的数据
      const data: ToastPanelData = {
        notification: toastMessage,
        parent: this.elementRef, // 用于绝对定位
        panelClass: [], // SnackBar 不使用自定义面板样式
        destroyToastComponent: () => {} // SnackBar 会自动处理销毁
      };

      // 配置 SnackBar 的显示参数
      const config: MatSnackBarConfig = {
        horizontalPosition: toastMessage.horizontalPosition || 'left',
        // 垂直位置：移动端固定在底部，桌面端可配置
        verticalPosition: !isGtSm ? 'bottom' : (toastMessage.verticalPosition || 'top'),
        viewContainerRef: this.viewContainerRef,
        duration: toastMessage.duration,  // 自动关闭时间
        panelClass: toastMessage.panelClass, // 自定义样式类
        data // 传递给组件的数据
      };

      // 打开 SnackBar
      this.snackBarRef = this.snackBar.openFromComponent(ToastComponent, config);
      
      // 如果设置了自动关闭且需要强制关闭，启动定时器
      // forceDismiss: 强制关闭，即使用户没有交互也关闭
      if (toastMessage.duration && toastMessage.duration > 0 && toastMessage.forceDismiss) {
        this.setDismissTimeout(toastMessage.duration);
      }
    });
  }

  /** 设置自动关闭定时器 
   * 
   * @param duration - 延迟关闭的时间（毫秒）
  */
  private setDismissTimeout(duration: number): void {
    // 如果已有定时器，先清除（避免重复定时器）
    if (this.dismissTimeout) {
      clearTimeout(this.dismissTimeout);
      this.dismissTimeout = undefined;
    }
    
    // 设置新的定时器
    this.dismissTimeout = setTimeout(() => {
      // 尝试关闭 SnackBar 模式（安全调用）
      const snackBarInstance = this.snackBarRef?.instance as ToastComponent;
      if (snackBarInstance) {
        snackBarInstance.actionButton._elementRef.nativeElement.click();
      }
      
      // 尝试关闭 Toast Panel 模式（安全调用）
      if (this.toastPanelRef) {
        this.toastPanelRef.instance.actionButton._elementRef.nativeElement.click();
      }
      
      // 清除定时器引用
      this.dismissTimeout = undefined;
    }, duration);
  }

  /** 判断是否应该显示消息 - 检查内容、目标和去重 */
  private shouldDisplayMessage(toastMessage: ToastMessage): boolean {
    // 检查消息内容是否有效
    if (!toastMessage?.message) {
      return false;
    }
    
    // 检查目标容器是否匹配
    const target = toastMessage.target || 'root';
    if (this.toastTarget !== target) {
      return false;
    }
    
    // 去重判断：如果是相同的消息和类型，不重复显示
    return !this.currentMessage || 
           this.currentMessage.message !== toastMessage.message ||
           this.currentMessage.type !== toastMessage.type;
  }

  /** 组件销毁时清理资源 */
  ngOnDestroy(): void {
    // 1. 清理动态创建的 Toast 组件（自定义面板模式）
    if (this.toastPanelRef) {
      this.viewContainerRef.detach(0);
      this.toastPanelRef.destroy();
    }
    
    // 2. 取消通知消息订阅
    this.notificationSubscription?.unsubscribe();
    
    // 3. 取消隐藏通知订阅
    this.hideNotificationSubscription?.unsubscribe();
    
    // 4. 清除自动关闭定时器
    if (this.dismissTimeout) {
      clearTimeout(this.dismissTimeout);
      this.dismissTimeout = undefined;
    }
  }
}

